<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>function name</title>
    <style>
        #results li.pass {
            color: green;
        }

        #results li.fail {
            color: red;
            text-decoration: line-through;
        }
    </style>
</head>
<body>

<div id="results"></div>

<script>
    function assert(value, desc) {
        let li = document.createElement('li');
        li.className = value ? 'pass' : 'fail';
        li.appendChild(document.createTextNode(desc));
        document.getElementById('results').appendChild(li);
    }
    //    function isNimble() {
    //        return true;
    //    }
    //    assert(typeof window.isNimble === 'function', "isNimble() defined");
    //    assert(isNimble.name === "isNimble", "isNimble() has a name");
    //
    //    window.canFly = function () {
    //        return true;
    //    };
    //    assert(typeof window.canFly === 'function', 'canFly() defined');
    //    assert(canFly.name === '', 'canFly() has no name');
    //
    //    window.isDeadly = function () {
    //        return true;
    //    };
    //    assert(typeof window.isDeadly === 'function', 'isDeadly() defined');
    //    function outer() {
    //        assert(typeof inner === "function", 'inner() in scope before declaration');
    //        function inner() {
    //        }
    //
    //        assert(typeof inner === 'function', 'inner() in scope after declaration');
    //        assert(window.inner === undefined, 'inner() not in global scope');
    //    }
    //    outer();
    //
    //    assert(window.inner === undefined, 'inner() still not in global scope');
    //
    //    window.wieldsSword = function swingsSword() {
    //        return true;
    //    };
    //    assert(window.wieldsSword.name === 'swingsSword', "wieldSword's real name is swingsSword");


    //声明与作用域
    function test() {
        assert(typeof outer === "function", 'outer() is in scope');
        assert(typeof inner === "function", 'inner() is in scope');
        assert(typeof a === 'number', 'a is in scope');
        assert(typeof b === 'number', 'b is in scope');
        assert(typeof c === 'number', 'c is in scope');
    }
    assert(true, '|----- OUTSIDE OUTER -----|');
    test()
    function outer() {
        assert(true, '|----- INSIDE OUTER, BEFORE a -----|');
        test()
        var a = 1;
        assert(true, '|----- INSIDE OUTER, AFTER a -----|');
        test()
        function inner() {/*does nothing*/}
        var b = 2;
        assert(true, '|----- INSIDE OUTER, AFTER inner() AND b -----|');
        test()
        if (a === 1) {
            var c = 3;
            assert(true, '|----- INSIDE OUTER, INSIDE IF -----|');
            test()
        }
        assert(true, '|----- INSIDE OUTER, OUTSIDE IF -----|');
        test()
    }
    outer();
    assert(true, '|----- AFTER OUTER -----|')
    test()

    assert(true,"--------------------------------------------------------------------------------")

    assert(true, '|----- OUTSIDE OUTER -----|');
    assert(typeof outer === "function", 'outer() is in scope');
    assert(typeof inner === "function", 'inner() is in scope');
    assert(typeof a === 'number', 'a is in scope');
    assert(typeof b === 'number', 'b is in scope');
    assert(typeof c === 'number', 'c is in scope');
    function outer() {
        assert(true, '|----- INSIDE OUTER, BEFORE a -----|');
        assert(typeof outer === "function", 'outer() is in scope');
        assert(typeof inner === "function", 'inner() is in scope');
        assert(typeof a === 'number', 'a is in scope');
        assert(typeof b === 'number', 'b is in scope');
        assert(typeof c === 'number', 'c is in scope');
        var a = 1;
        assert(true, '|----- INSIDE OUTER, AFTER a -----|');
        assert(typeof outer === "function", 'outer() is in scope');
        assert(typeof inner === "function", 'inner() is in scope');
        assert(typeof a === 'number', 'a is in scope');
        assert(typeof b === 'number', 'b is in scope');
        assert(typeof c === 'number', 'c is in scope');
        function inner() {/*does nothing*/}
        var b = 2;
        assert(true, '|----- INSIDE OUTER, AFTER inner() AND b -----|');
        assert(typeof outer === "function", 'outer() is in scope');
        assert(typeof inner === "function", 'inner() is in scope');
        assert(typeof a === 'number', 'a is in scope');
        assert(typeof b === 'number', 'b is in scope');
        assert(typeof c === 'number', 'c is in scope');
        if (a === 1) {
            var c = 3;
            assert(true, '|----- INSIDE OUTER, INSIDE IF -----|');
            assert(typeof outer === "function", 'outer() is in scope');
            assert(typeof inner === "function", 'inner() is in scope');
            assert(typeof a === 'number', 'a is in scope');
            assert(typeof b === 'number', 'b is in scope');
            assert(typeof c === 'number', 'c is in scope');
        }
        assert(true, '|----- INSIDE OUTER, OUTSIDE IF -----|');
        assert(typeof outer === "function", 'outer() is in scope');
        assert(typeof inner === "function", 'inner() is in scope');
        assert(typeof a === 'number', 'a is in scope');
        assert(typeof b === 'number', 'b is in scope');
        assert(typeof c === 'number', 'c is in scope');

    }
    outer();
    assert(true, '|----- AFTER OUTER -----|')
    assert(typeof outer === "function", 'outer() is in scope');
    assert(typeof inner === "function", 'inner() is in scope');
    assert(typeof a === 'number', 'a is in scope');
    assert(typeof b === 'number', 'b is in scope');
    assert(typeof c === 'number', 'c is in scope');
</script>
</body>
</html>